﻿/*!	@file	r_raytrace_object_sphere.h
	@brief	raytrace球オブジェクト
Copyright (c) 2011 Yuya Yamaguchi

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#ifndef _R_RAYTRACE_OBJECT_SPHERE_H_
#define _R_RAYTRACE_OBJECT_SPHERE_H_

#include "r_raytrace_object.h"
#include "r_raytrace_micro_polygon.h"
#include "../math/r_math_sphere.h"
#include "../math/r_math_ray.h"

namespace r{
	namespace raytrace{
		//! レイトレース対象オブジェクト(球)
		/*!
		*/
		class ObjectSphere : public Object{
		public:
			//! コンストラクタ
			ObjectSphere()
			: geom(0.0f, 0.0f, 0.0f, 1.0f)
			{
			}
			//! デストラクタ
			virtual ~ObjectSphere()
			{
			}
		public:
			//! 球の情報を設定
			void	setSphere( const r::math::Sphere& sphere )
			{
				geom = sphere;
			}
		public:
			//! レイキャスト関数
			/*! 交差しているかのみを判定する
			@param	ray	レイ情報
			@retval	交点までの距離
			@retval	0>ret 交点無し
			*/
			virtual r_f32	rayCast( const r::math::Ray& ray )const{
				return detectCross(ray);
			}

			//! レイシェイド
			/*! 評価対象のサーフェス情報を取得します
			@param	ray		レイ情報
			@param	poly	交点の情報
			@retval	交点までの距離
			@retval	0>ret 交点無し
			*/
			virtual r_f32	rayShade( const r::math::Ray& ray, MicroPolygon& poly )const{
				r_f32 distance = detectCross(ray);
				if( distance < 0.0f ){
					return -1.0f;
				}
				// 交点
				poly.position = ray.position + ray.direction * distance;
				// 法線を求める
				poly.baseNormal = poly.position - geom.position;
				poly.baseNormal.normalize();
				// 最終的にココでサーフェス情報全部書き込み
				return distance;
			}
		protected:
			//! 交点計算
			/*!
			*/
			inline r_f32	detectCross( const r::math::Ray& ray )const
			{
				r_f32 a = ray.direction.dot(ray.direction);
				r::math::Vector3D centerdir = ray.position - geom.position;
				r_f32 b = centerdir.dot(ray.direction) * 2.0f;
				r_f32 c = centerdir.dot(centerdir) - geom.radius * geom.radius;

				r_f32 t0 = b * b - 4.0f * a * c;
				if( t0 < 0.0f ){
					return -1.0f;
				}
				// 交点までの距離を求める
				r_f32 invA = 1.0f / a;
				r_f32 t1 = -b * 0.5f * invA;
				r_f32 t2 = ::sqrtf(t0) * 0.5f * invA;
				r_f32 d = ( t1 - t2 > 0.0f ) ? t1 - t2 : t1 + t2;
				return d;
			}
		private:
			//! 幾何学情報
			r::math::Sphere		geom;
		};
	}
}

#endif // _R_RAYTRACE_OBJECT_SPHERE_H_
